package com.cgs.query.server.aspect

import com.cgs.query.exception.QueryException
import com.cgs.query.executor.ExecuteArgs
import com.cgs.query.executor.ExecuteAspectHandler
import mu.KotlinLogging
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
import org.springframework.scheduling.annotation.Async

private val logger = KotlinLogging.logger { }

/**
 * 对远程执行进行记录等工作
 */
@Aspect
@ConditionalOnExpression("\${sql.runner.actuator.enabled:true}")
open class ExecuteAspect {

    @Autowired(required = false)
    private var executeAspectHandlers: List<ExecuteAspectHandler>? = listOf()

    @Pointcut("execution(* com.cgs.query.server.service.ServerQueryService.execute(..))")
    fun executePointCut() {
    }

    init {
        logger.info { "将对IQueryService接口进行监控" }
    }

    @Around("executePointCut()")
    @Throws(Throwable::class)
    fun doAround(pjp: ProceedingJoinPoint): Any? {
        var result: Any? = null
        try {
            before(pjp.args.copyOf())
            return pjp.proceed().apply { result = this }
        } catch (e: QueryException) {
            exception(e)
            throw e
        } finally {
            after(result)
        }
    }

    @Async
    open fun before(args: Array<Any>) {
        val executeArgs = ExecuteArgs(args)
        executeAspectHandlers?.forEach { it.before(executeArgs) }
    }

    @Async
    open fun after(result: Any?) {
        executeAspectHandlers?.forEach { it.after(result) }
    }

    @Async
    open fun exception(e: QueryException) {
        executeAspectHandlers?.forEach { it.exception(e) }
    }
}
